﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using Kooboo.Commerce.Contexts.Carts;
using Kooboo.Commerce.Contexts.Products;
using Kooboo.IoC;
using Kooboo.Connect;
using Kooboo.Commerce.Contexts.Customers;
using Kooboo.Commerce.Contexts.Countries;
using Kooboo.Commerce.Contexts.Payments;
using Kooboo.Commerce.Contexts.Shippings;
using Kooboo.Commerce.Contexts.Orders;
using Kooboo.Commerce.AddIn;
using Kooboo.Commerce.Contexts.ShopSettings;


namespace Kooboo.Commerce.Services
{
    public class CartService : ServiceBase
    {
        #region Private
        static string CartIdOnClient = "__CartId__";


        int? GetCartId()
        {

            var cartOnClient = HttpContext.Current.Request.Cookies[CartIdOnClient];

            if (cartOnClient == null || string.IsNullOrWhiteSpace(cartOnClient.Value))
            {
                cartOnClient = HttpContext.Current.Response.Cookies[CartIdOnClient];

            }


            int cartId;

            if (cartOnClient != null)
            {
                if (int.TryParse(cartOnClient.Value, out cartId))
                {
                    return cartId;
                }
            }

            return null;

        }
        #endregion

        public Cart OpenCart()
        {
            var cart = this.Actor.OpenCart(this.GetCartId());


            //HttpContext.Current.Response.Cookies.Remove(CartIdOnClient);
            //HttpContext.Current.Request.Cookies.Remove(CartIdOnClient);

            var cookie = HttpContext.Current.Response.Cookies[CartIdOnClient];

            if (cookie == null)
            {
                cookie = new HttpCookie(CartIdOnClient);
                HttpContext.Current.Response.AppendCookie(cookie);
            }

            cookie.Value = cart.Id.ToString();
            cookie.Expires = DateTime.Now.AddDays(7);
            cookie.Path = "/";



            var model = new Cart();

            model.Id = cart.Id;
            model.Items = cart.CartItems.Select(m => new CartItem
            {
                Discount = m.Discount,
                Id = m.Id,
                //Image = m.Product.ProductImages.Where(n => n.CoverImage).Select(n => n.CartUrl(Configuration.ProductImageFolder)).FirstOrDefault(),
                Image = GetCartItemImageUrl(m.Product.ProductImages),
                ProductId = m.Product.Id,
                ProductName = m.ProductName,
                Quantity = m.Quantity,
                SaleItemId = m.SaleItem.Id,
                SubTotal = m.SubTotal,
                TaxCost = m.TaxCost,
                UnitPrice = m.SaleItem.RetailPrice,
                Sku = m.SaleItem.SKU,
                Total = m.Total
            })
            .ToList();

            model.OrderDiscount = cart.Discount;
            model.PaymentMethodCost = cart.PaymentMethodCost;



            model.ShippingCost = cart.ShippingCost;
            model.SubTotal = cart.SubTotal;
            model.TaxCost = cart.TotalTaxCost;
            model.TotalDiscount = cart.TotalDiscount;
            model.Total = cart.Total;

            return model;
        }

        public IEnumerable<IAddress> GetCurrentAddresses()
        {
            var user = ContextContainer.Current.Resolve<User>();

            if (user == null)
            {
                return Enumerable.Empty<IAddress>();
            }
            else
            {

                var customer = this.Actor.QueryCustomers()
                    .Where(i => i.UserName == user.Name)
                    .FirstOrDefault();

                if (customer == null)
                {
                    return Enumerable.Empty<IAddress>();
                }
                else
                {
                    return customer.Addresses;
                }
            }
        }

        /// <summary>
        /// create a new shopping cart
        /// </summary>
        void Close()
        {
            //clear cart's cookie
            var cookie = new HttpCookie(CartIdOnClient, "-1");

            cookie.Expires = DateTime.Now.AddDays(-7);

            HttpContext.Current.Response
                .Cookies
                .Add(cookie);
        }

        #region ShippingInfo

        public ShippingInfo GetShippingInfo()
        {
            var cart = this.Actor.QueryCarts().Where(i => i.Id == this.GetCartId()).FirstOrDefault();
            return new ShippingInfo
            {
                FirstName = cart.FirstName,
                LastName = cart.LastName,
                Phone = cart.Phone,
                Address1 = cart.Address1,
                Address2 = cart.Address2,
                City = cart.City,
                Postcode = cart.Postcode,
                State = cart.State,
                Country = cart.Country,
                Shipping = cart.Shipping == null ? -1 : cart.Shipping.Id,
                ShippingName = cart.Shipping == null ? "" : cart.Shipping.Name
            };

        }

        public void Update(ShippingInfo info)
        {
            var cart = this.Actor.QueryCarts().Where(i => i.Id == this.GetCartId()).FirstOrDefault();

            cart.FirstName = info.FirstName;
            cart.LastName = info.LastName;
            cart.Phone = info.Phone;
            cart.Address1 = info.Address1;
            cart.Address2 = info.Address2;
            cart.City = info.City;
            cart.Postcode = info.Postcode;
            cart.State = info.State;
            cart.Country = this.Actor.QueryCountries()
                .Where(i => i.CountryCode == info.Country)
                .Select(i => i.CountryName)
                .FirstOrDefault();

            if (info.Shipping > 0)
            {
                cart.Shipping = this.Actor.QueryShippings()
                    .Where(i => i.Id == info.Shipping)
                    .FirstOrDefault();
            }
            this.Actor.Put(cart);
        }

        #endregion

        #region CartItem
        public void AddItem(int saleItemId, int quantity)
        {
            var cart = this.Actor.OpenCart(this.GetCartId());

            var saleitem = this.Actor.QueryProducts().SelectMany(i => i.SaleItems)
                  .Where(i => i.Id == saleItemId)
                  .FirstOrDefault();

            var find = cart.CartItems.Where(i => i.SaleItem.Id == saleItemId).FirstOrDefault();
            if (find == null)
            {
                find = ObjectContainer.CreateInstance<ICartItem>();

                find.SaleItem = saleitem;
                find.Product = saleitem.Product;
                find.Quantity = quantity;

                cart.CartItems.Add(find);
            }
            else
            {
                find.Quantity += quantity;
            }

            find.ProductName = saleitem.Product.Name;
            find.SKU = saleitem.SKU;
            find.UnitPrice = saleitem.RetailPrice;

            this.Actor.Put(cart);
        }

        public void RemoveItem(int id, int quantity = int.MaxValue)
        {
            var cart = this.Actor.OpenCart(this.GetCartId());

            var find = cart.CartItems.Where(i => i.Id == id).FirstOrDefault();
            if (find != null)
            {
                if (find.Quantity > quantity)
                {
                    find.Quantity = find.Quantity - quantity;
                }
                else
                {
                    cart.CartItems.Remove(find);
                }

                this.Actor.Put(cart);
            }
        }

        public void UpdateItemQuntity(Int32 saleItemId, Int32 quantity)
        {
            var cart = this.Actor.OpenCart(this.GetCartId());

            var saleitem = this.Actor.QueryProducts().SelectMany(i => i.SaleItems)
                  .Where(i => i.Id == saleItemId)
                  .FirstOrDefault();

            var find = cart.CartItems.Where(i => i.SaleItem.Id == saleItemId).FirstOrDefault();
            if (find == null)
            {
                if (quantity > 0 && find.Quantity != quantity)
                {
                    find = ObjectContainer.CreateInstance<ICartItem>();

                    find.SaleItem = saleitem;
                    find.Product = saleitem.Product;
                    find.Quantity = quantity;

                    cart.CartItems.Add(find);
                }
                else
                {
                    return;
                }
            }
            else
            {
                if (quantity > 0)
                {
                    find.Quantity = quantity;
                }
                else //remove
                {
                    cart.CartItems.Remove(find);
                    this.Actor.Put(cart);
                    return;
                }
            }

            find.ProductName = saleitem.Product.Name;
            find.SKU = saleitem.SKU;
            find.UnitPrice = saleitem.RetailPrice;

            this.Actor.Put(cart);
        }

        #endregion

        #region PaymentInfo

        public PaymentInfo GetPaymentInfo()
        {
            var cart = this.Actor.QueryCarts().Where(i => i.Id == this.GetCartId()).FirstOrDefault();
            return new PaymentInfo
            {
                InvoiceFirstName = cart.InvoiceFirstName,
                InvoiceLastName = cart.InvoiceLastName,
                InvoicePhone = cart.InvoicePhone,
                InvoiceAddress1 = cart.InvoiceAddress1,
                InvoiceAddress2 = cart.InvoiceAddress2,
                InvoiceCity = cart.InvoiceCity,
                InvoicePostcode = cart.InvoicePostcode,
                InvoiceState = cart.InvoiceState,
                InvoiceCountry = cart.InvoiceCountry,
                Payment = cart.Payment == null ? "" : cart.Payment.MethodName,
                Coupon = cart.Coupon,
                UseInvoiceAddress = cart.UseInvoiceAddress
            };
        }

        public void Update(PaymentInfo info)
        {
            var cart = this.Actor.QueryCarts().Where(i => i.Id == this.GetCartId()).FirstOrDefault();

            cart.UseInvoiceAddress = info.UseInvoiceAddress;
            cart.InvoiceFirstName = info.InvoiceFirstName;
            cart.InvoiceLastName = info.InvoiceLastName;
            cart.InvoicePhone = info.InvoicePhone;
            cart.InvoiceAddress1 = info.InvoiceAddress1;
            cart.InvoiceAddress2 = info.InvoiceAddress2;
            cart.InvoiceCity = info.InvoiceCity;
            cart.InvoicePostcode = info.InvoicePostcode;
            cart.InvoiceState = info.InvoiceState;
            cart.InvoiceCountry = this.Actor.QueryCountries()
                .Where(i => i.CountryCode == info.InvoiceCountry)
                .Select(i => i.CountryName)
                .FirstOrDefault();

            if (!String.IsNullOrEmpty(info.Payment))
            {
                cart.Payment = this.Actor.QueryPayments()
                    .Where(i => i.MethodName == info.Payment)
                    .FirstOrDefault();
            }

            cart.Coupon = info.Coupon;

            this.Actor.Put(cart);
        }

        #endregion

        public void UpdateShippingAndPaymentMethod(int shippingMethod, String payment, String couponCode)
        {
            var cart = this.Actor.QueryCarts().Where(i => i.Id == this.GetCartId()).FirstOrDefault();

            cart.Shipping = this.Actor.QueryShippings()
                    .Where(i => i.Id == shippingMethod)
                    .FirstOrDefault();

            cart.Payment = this.Actor.QueryPayments()
               .Where(i => i.MethodName == payment)
               .FirstOrDefault();

            cart.Coupon = couponCode;

            this.Actor.Put(cart);
        }

        public IOrder Purchase(string remark, String thankYouPage)
        {
            var cart = this.Actor.QueryCarts()
                .Where(i => i.Id == this.GetCartId())
                .FirstOrDefault();

            cart.Remark = remark;

            var order = this.Actor.Order(cart);

            if (order != null)
            {
                this.Close();

                var shopSetting = this.Actor.GetShopSettings();
                var method = ObjectContainer.CreateInstances<IPaymentMethod>()
                    .Where(i => i.Name == order.PaymentName)
                    .FirstOrDefault();

                method.ThankYouPageUrl = thankYouPage;

                method.TryToPay(order, shopSetting.CurrencyISOCode);

            }
            return order;
        }

        string GetCartItemImageUrl(List<IProductImage> productImages)
        {
            String cartImage = String.Empty;

            if (productImages != null && productImages.Count >= 0)
            {
                cartImage = productImages.Where(n => n.CoverImage).Select(n => n.CartUrl(Configuration.ProductImageFolder)).FirstOrDefault();
            }
            if (String.IsNullOrEmpty(cartImage))
            {
                return Configuration.ImageNotAvailable_Thumbnail;
            }
            return cartImage;
        }
    }

    public class ShippingInfo
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Phone { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string City { get; set; }
        public string Postcode { get; set; }
        public string Country { get; set; }
        public string State { get; set; }
        public int Shipping { get; set; }
        public string ShippingName { get; set; }
    }

    public class PaymentInfo
    {
        public string InvoiceFirstName { get; set; }
        public string InvoiceLastName { get; set; }
        public string InvoicePhone { get; set; }
        public string InvoiceAddress1 { get; set; }
        public string InvoiceAddress2 { get; set; }
        public string InvoiceCity { get; set; }
        public string InvoicePostcode { get; set; }
        public string InvoiceCountry { get; set; }
        public string InvoiceState { get; set; }
        public string Coupon { get; set; }
        public string Payment { get; set; }
        public Boolean UseInvoiceAddress { get; set; }
    }

    public class AddressInfo
    {
        public PaymentInfo Payment { get; set; }

        public ShippingInfo Shipping { get; set; }
    }
}
